#pragma once

#include <iostream>
#include <string>
#include <jsoncpp/json/json.h> //key-value结构

// 报文格式: jsonstr长度\r\njsonstr\r\n

// 请求
class Request
{
public:
    Request() {}
    // 序列化: "_x" "_oper" "_y"  --->  "-x" "-r-n" "_oper" "-r-n" "_y"
    bool Serialize(std::string *out)
    {
        Json::Value root;
        root["x"] = _x;
        root["oper"] = _oper;
        root["y"] = _y;

        Json::StyledWriter writer;
        *out = writer.write(root);
        if (out->empty())
            return false;
        return true;
    }

    // 反序列化
    bool Deserialize(std::string &in)
    {
        Json::Value root;
        Json::Reader reader;
        bool ret = reader.parse(in, root);
        if (!ret)
            return false;
        _x = root["x"].asInt();
        _y = root["y"].asInt();
        _oper = root["oper"].asInt();
        return true;
    }
    ~Request() {}

public:
    // 规则1: x oper y
    int _x;
    int _y;
    char _oper;
};

// 应答
class Response
{
public:
    Response(): _result(0), _code(0)
    {}
    // 序列化
    bool Serialize(std::string *out)
    {
        Json::Value root;
        root["result"] = _result;
        root["code"] = _code;

        Json::StyledWriter writer;
        *out = writer.write(root);
        if (out->empty())
            return false;
        return true;
    }

    // 反序列化
    bool Deserialize(std::string &in)
    {
        Json::Value root;
        Json::Reader reader;
        bool ret = reader.parse(in, root);
        if (!ret)
            return false;
        _result = root["result"].asInt();
        _code = root["code"].asInt();
        return true;
    }

    void SetResult(int ret)
    {
        _result = ret;
    }

    void SetCode(int code)
    {
        _code = code;
    }

    void Print()
    {
        std::cout << _result << " ["<< _code << "]" << std::endl;
    }

    ~Response() {}

private:
    int _result; // x oper y的结果就发在result中
    int _code;   // 正确码：判断结果是否正确(0为正确, 其他为错误)
};

static const std::string sep = "\r\n"; // 间隔符

// 协议
class Protocol
{
public:
    // 封装报文
    static std::string Package(const std::string &jsonstr)
    {
        if (jsonstr.empty())
            return std::string(); // 返回一个空字符串
        std::string json_len = std::to_string(jsonstr.size());
        return json_len + sep + jsonstr + sep;
    }

    static bool DigitSafeCheck(std::string str)
    {
        for(auto c : str)
        {
            if(!(c >= '0' && c <='9'))
            {
                return false;
            }
        }
        return true;
    }

    // 解包
    //  str: 从网络里读取到的字符串, 输入输出型参数
    //  package: 从str中截取道德完整形式报文, 输出型参数
    static int Unpack(std::string &origin_str, std::string *package)
    {
        if(!package)
            return 0;
        auto pos = origin_str.find(sep);//从左向右找到第一个分隔符
        if(pos == std::string::npos)//没找到间隔符
            return 0;
        
        // 获取一条报文长度
        //此时最少收到了一个报文的长度:jsonstr_len\r\n
        //截取第一部分: jsonstr的长度(字符型)
        std::string str_len = origin_str.substr(0, pos);

        if(!DigitSafeCheck(str_len))//协议是错的
        {
            return -1;
        }
        // 字符型长度转整数型
        int digit_len = std::stoi(str_len);
        // 一条完整报文长度
        int target_len = str_len.size() + digit_len + 2 * sep.size();

        //读取到的报文不完整或没有报文
        if(origin_str.size() < target_len)
        {
            return 0;
        }

        // 到这一步时, 接收到的字符串内部至少含有一条完整的报文
        // 从间隔符后按照jsonstr有效长度开始截取报文
        *package = origin_str.substr(pos + sep.size(), digit_len);
        origin_str.erase(0, target_len);//截取完后，将该报文从字符串中删除
        return package->size();
    }
};